using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Common.Utilities;
using Common.Utilities.Dispatcher;

namespace Workflows.Components
{
    /// <summary>
    /// 
    /// </summary>
    public partial class GlobalVariableSetterEditor : Form, IComponentEditor 
    {
        private object _OwnerActivityNode;
        private GlobalVariableSetterComponent _SetterComponent;
        private Dictionary<string, GlobalVariable> _GlobalVariables;
        private WorkflowComponentBase[] _FromComponents;
        // private Dictionary<string, ComponentField> _FromMemberTypes;
        // srcComponentID -> ( srcfieldname -> (tgtFieldName -> codesnippet))
        private Dictionary<Guid, Dictionary<string, Dictionary<string, string>>>
            _TransformationCodeSnippetsByGlobalVarNames;

        /// <summary>
        /// 
        /// </summary>
        public GlobalVariableSetterEditor()
        {
            InitializeComponent();
        }

        private void GlobalVariableSetterEditor_Load(object sender, EventArgs e)
        {
            this._FromComponents = null;
            this._GlobalVariables=new Dictionary<string, GlobalVariable>();
            this._TransformationCodeSnippetsByGlobalVarNames =
                new Dictionary<Guid, Dictionary<string, Dictionary<string, string>>>();
            // this._FromMemberTypes = new Dictionary<string, ComponentField>();
            this._SetterComponent=new GlobalVariableSetterComponent();
        }

        public event UpdateComponentSettings UpdateComponentSettingEvent;

        public object OwnerActivityNode
        {
            get { return _OwnerActivityNode; }
            set { _OwnerActivityNode = value; }
        }

        public Type WorkflowComponentType
        {
            get { return typeof(GlobalVariableSetterComponent); }
        }

        public void LoadSettings(
            GlobalVariable[] globalVars, 
            WorkflowComponentBase[] fromComponents, 
            object activityNode, 
            WorkflowComponentBase wfComponent)
        {
            this.cbo_GlobalVariableNames.Items.Clear();
            this.cbo_GlobalVariableNames.SelectedIndex = -1;
            this.cbo_GlobalVariableNames.Text = string.Empty;
            this._GlobalVariables=new Dictionary<string, GlobalVariable>();
            if(globalVars !=null && globalVars.Length>0)
            {
                foreach(GlobalVariable globalVar in globalVars)
                {
                    this._GlobalVariables.Add(globalVar.VarName,globalVar);
                    this.cbo_GlobalVariableNames.Items.Add(globalVar.VarName);
                }
            }
            this._FromComponents = fromComponents;
            this._OwnerActivityNode = activityNode;
            this._SetterComponent = (GlobalVariableSetterComponent) wfComponent;
            this.cbo_SrcComponents.Items.Clear();
            if(this._FromComponents !=null && this._FromComponents.Length>0)
            {
                foreach(WorkflowComponentBase fromComponent in this._FromComponents)
                {
                    this.cbo_SrcComponents.Items.Add(fromComponent.ComponentName);
                }
            }

            this.dv_Bindings.Rows.Clear();
            this._TransformationCodeSnippetsByGlobalVarNames =
                new Dictionary<Guid, Dictionary<string, Dictionary<string, string>>>();
            
            if(this._SetterComponent.Setters !=null && this._SetterComponent.Setters.Count>0)
            {
                foreach (FieldSetter setter in this._SetterComponent.Setters)
                {
                    DataGridViewRow dr = new DataGridViewRow();
                    DataGridViewTextBoxCell cellSrcComponent = new DataGridViewTextBoxCell();
                    cellSrcComponent.Value = setter.SrcComponentID.ToString();
                    dr.Cells.Add(cellSrcComponent);
                    DataGridViewTextBoxCell cellSrcComponentName = new DataGridViewTextBoxCell();
                    cellSrcComponentName.Value = string.Empty;
                    if(this._FromComponents !=null && this._FromComponents.Length>0)
                    {
                        foreach (WorkflowComponentBase fromComponent in this._FromComponents)
                        {
                            if (fromComponent.ComponentID == setter.SrcComponentID)
                            {
                                cellSrcComponentName.Value = fromComponent.ComponentName;
                                break;
                            }
                        }
                    }
                    dr.Cells.Add(cellSrcComponentName);
                    DataGridViewTextBoxCell cellSrcField = new DataGridViewTextBoxCell();
                    cellSrcField.Value = setter.SrcFieldName;
                    dr.Cells.Add(cellSrcField);
                    DataGridViewTextBoxCell cellTgtField = new DataGridViewTextBoxCell();
                    cellTgtField.Value = setter.TgtFieldName;
                    dr.Cells.Add(cellTgtField);
                    DataGridViewImageCell cellTransform = new DataGridViewImageCell();
                    if (this.IsFieldTypeCompatible(setter.SrcComponentID, setter.SrcFieldName, setter.TgtFieldName))
                    {
                        cellTransform.Value = this.imageList1.Images[0];
                    }
                    else
                    {
                        cellTransform.Value = this.imageList1.Images[2];
                    }
                    dr.Cells.Add(cellTransform);
                    this.dv_Bindings.Rows.Add(dr);

                    if (!string.IsNullOrEmpty(setter.TransformationCodeSnippet))
                    {
                        if(this._TransformationCodeSnippetsByGlobalVarNames.ContainsKey(setter.SrcComponentID))
                        {
                            Dictionary<string, Dictionary<string, string>> srcField_TgtField_Code =
                                this._TransformationCodeSnippetsByGlobalVarNames[setter.SrcComponentID];
                            if(srcField_TgtField_Code.ContainsKey(setter.SrcFieldName))
                            {
                                Dictionary<string, string> tgtField_Code = srcField_TgtField_Code[setter.SrcFieldName];
                                if(!tgtField_Code.ContainsKey(setter.TgtFieldName))
                                    tgtField_Code.Add(setter.TgtFieldName,setter.TransformationCodeSnippet);
                                srcField_TgtField_Code[setter.SrcFieldName] = tgtField_Code;
                            }
                            else
                            {
                                Dictionary<string,string> tgtField_Code=new Dictionary<string, string>();
                                tgtField_Code.Add(setter.TgtFieldName,setter.TransformationCodeSnippet);
                                srcField_TgtField_Code.Add(setter.SrcFieldName,tgtField_Code);
                            }
                            this._TransformationCodeSnippetsByGlobalVarNames[setter.SrcComponentID] =
                                srcField_TgtField_Code;
                        }
                        else
                        {
                            Dictionary<string, Dictionary<string, string>> srcField_TgtField_Code =
                                new Dictionary<string, Dictionary<string, string>>();
                            Dictionary<string, string> tgtField_Code = new Dictionary<string, string>();
                            tgtField_Code.Add(setter.TgtFieldName,setter.TransformationCodeSnippet);
                            srcField_TgtField_Code.Add(setter.SrcFieldName,tgtField_Code);
                            this._TransformationCodeSnippetsByGlobalVarNames.Add(setter.SrcComponentID,
                                                                                 srcField_TgtField_Code);
                        }
                    }
                }
            }
        }

        private void cbo_GlobalVariableNames_SelectedIndexChanged(object sender, EventArgs e)
        {
            if(this.cbo_GlobalVariableNames.SelectedIndex>=0)
            {
                string globalVarName = this.cbo_GlobalVariableNames.SelectedItem.ToString();
                if(this._GlobalVariables.ContainsKey(globalVarName))
                {
                    GlobalVariable globalVar = this._GlobalVariables[globalVarName];
                    this.lbl_GlobalVarDataType.Text = globalVar.DataType.ToString();
                }
            }
        }

        private void cbo_SrcFieldNames_SelectedIndexChanged(object sender, EventArgs e)
        {
            if(this.cbo_SrcFieldNames.SelectedIndex>=0 && this.cbo_SrcComponents.SelectedIndex>=0)
            {
                string srcComponentName = this.cbo_SrcComponents.Text;
                string fieldName = this.cbo_SrcFieldNames.SelectedItem.ToString();
                if(this._FromComponents !=null && this._FromComponents.Length>0)
                {
                    foreach(WorkflowComponentBase fromComponent in this._FromComponents)
                    {
                        if(fromComponent.ComponentName==srcComponentName)
                        {
                            Dictionary<string, Type> outputMembers =
                                fromComponent.Output.GetBindableMemberNames(new Type[] {typeof (ResultBase)});
                            foreach(string outputFieldName in outputMembers.Keys)
                            {
                                if(outputFieldName==fieldName)
                                {
                                    this.lbl_SrcFieldDataType.Text = outputMembers[outputFieldName].ToString();
                                    break;
                                }
                            }
                            break;
                        }
                    }
                }
            }
        }

        private void btn_AddBinding_Click(object sender, EventArgs e)
        {
            if(this.cbo_SrcComponents.SelectedIndex>=0 &&
                this.cbo_GlobalVariableNames.SelectedIndex>=0 && 
                this.cbo_SrcFieldNames.SelectedIndex>=0)
            {
                DataGridViewRow dr=new DataGridViewRow();
                DataGridViewTextBoxCell cellSrcField=new DataGridViewTextBoxCell();

                string srcComponentName = this.cbo_SrcComponents.Text;
                Guid srcComponentID = Guid.Empty;
                if(this._FromComponents !=null && this._FromComponents.Length>0)
                {
                    foreach(WorkflowComponentBase fromComponent in this._FromComponents)
                    {
                        if(fromComponent.ComponentName==srcComponentName)
                        {
                            srcComponentID = fromComponent.ComponentID;
                            break;
                        }
                    }
                }
                DataGridViewTextBoxCell cellSrcID=new DataGridViewTextBoxCell();
                cellSrcID.Value = srcComponentID.ToString();
                dr.Cells.Add(cellSrcID);

                DataGridViewTextBoxCell cellSrcName=new DataGridViewTextBoxCell();
                cellSrcName.Value = srcComponentName;
                dr.Cells.Add(cellSrcName);

                string srcFieldName = this.cbo_SrcFieldNames.SelectedItem.ToString();
                cellSrcField.Value = srcFieldName;
                dr.Cells.Add(cellSrcField);

                DataGridViewTextBoxCell cellTgtField=new DataGridViewTextBoxCell();
                string tgtFieldName = this.cbo_GlobalVariableNames.SelectedItem.ToString();
                cellTgtField.Value = tgtFieldName;
                dr.Cells.Add(cellTgtField);
                DataGridViewImageCell cellTransform=new DataGridViewImageCell();
                if (this.IsFieldTypeCompatible(srcComponentID, srcFieldName, tgtFieldName))
                {
                    cellTransform.Value = this.imageList1.Images[0];
                }
                else
                {
                    cellTransform.Value = this.imageList1.Images[2];
                }
                dr.Cells.Add(cellTransform);
                this.dv_Bindings.Rows.Add(dr);
            }
        }

        private Type GetSrcFieldType(Guid srcComponentID, string srcFieldName)
        {
            Type srcFieldType = typeof(string);
            if (this._FromComponents != null && this._FromComponents.Length > 0)
            {
                foreach (WorkflowComponentBase fromComponent in this._FromComponents)
                {
                    if (fromComponent.ComponentID == srcComponentID)
                    {
                        Dictionary<string, Type> outputMembers =
                            fromComponent.Output.GetBindableMemberNames(new Type[] { typeof(ResultBase) });
                        foreach (string outputFieldName in outputMembers.Keys)
                        {
                            if (outputFieldName == srcFieldName)
                            {
                                srcFieldType = outputMembers[outputFieldName];
                                break;
                            }
                        }
                        break;
                    }
                }
            }
            return srcFieldType;
        }

        private Type GetSrcFieldType(WorkflowComponentBase srcComponent, string srcFieldName)
        {
            Type srcFieldType = typeof(string);
            Dictionary<string, Type> outputMembers =
                srcComponent.Output.GetBindableMemberNames(new Type[] {typeof (ResultBase)});
            foreach (string outputFieldName in outputMembers.Keys)
            {
                if (outputFieldName == srcFieldName)
                {
                    srcFieldType = outputMembers[outputFieldName];
                    break;
                }
            }
            return srcFieldType;
        }

        private bool IsFieldTypeCompatible(Guid srcComponentID, string srcFieldName, string tgtFieldName)
        {
            Type srcFieldType = this.GetSrcFieldType(srcComponentID, srcFieldName);
            GlobalVariable globalVar = this._GlobalVariables[tgtFieldName];
            if (srcFieldType == SimpleDataTypeUtil.ToSystemType(globalVar.DataType))
                return true;
            else
                return false;
        }

        public void SaveSettings()
        {
            List<FieldSetter> setters = new List<FieldSetter>();
            foreach(DataGridViewRow dr in this.dv_Bindings.Rows)
            {
                if(!dr.IsNewRow)
                {
                    if(dr.Cells[0].Value !=null && dr.Cells[1].Value !=null &&
                        dr.Cells[2] != null && dr.Cells[3] != null)
                    {
                        Guid srcComponentID=new Guid(dr.Cells[0].Value.ToString());
                        
                        if(this._FromComponents !=null && this._FromComponents.Length>0)
                        {
                            foreach(WorkflowComponentBase fromComponent in this._FromComponents)
                            {
                                if(fromComponent.ComponentID==srcComponentID)
                                {
                                    string srcFieldName = dr.Cells[2].Value.ToString();
                                    string tgtFieldName = dr.Cells[3].Value.ToString();
                                    {
                                        FieldSetter setter = new FieldSetter();
                                        setter.SrcComponentID = srcComponentID;
                                        setter.SrcFieldName = srcFieldName;
                                        setter.TgtFieldName = tgtFieldName;
                                        setter.TransformationCodeSnippet = string.Empty;
                                        if(this._TransformationCodeSnippetsByGlobalVarNames.ContainsKey(setter.SrcComponentID))
                                        {
                                            Dictionary<string, Dictionary<string, string>> srcField_TgtField_Code =
                                                this._TransformationCodeSnippetsByGlobalVarNames[setter.SrcComponentID];
                                            if(srcField_TgtField_Code.ContainsKey(setter.SrcFieldName))
                                            {
                                                Dictionary<string, string> tgtField_Code =
                                                    srcField_TgtField_Code[setter.SrcFieldName];
                                                if(tgtField_Code.ContainsKey(setter.TgtFieldName))
                                                {
                                                    setter.TransformationCodeSnippet =
                                                        tgtField_Code[setter.TgtFieldName];
                                                }
                                            }
                                        }

                                        setters.Add(setter);
                                    }
                                }
                            }
                        }
                        
                    }
                }
            }

            if (setters.Count > 0)
                this._SetterComponent.Setters = setters;
            else
                this._SetterComponent.Setters = null;
        }

        private void btn_OK_Click(object sender, EventArgs e)
        {
            this.SaveSettings();

            if(this.UpdateComponentSettingEvent !=null)
            {
                this.UpdateComponentSettingEvent(this._OwnerActivityNode, this._SetterComponent);
            }

            this.Close();
        }

        private void btn_Cancel_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void dv_Bindings_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            if(e.RowIndex>=0 && e.ColumnIndex==4)
            {
                DataGridViewRow dr = this.dv_Bindings.Rows[e.RowIndex];
                if(!dr.IsNewRow && dr.Cells[0].Value !=null && dr.Cells[1].Value !=null)
                {
                    Guid srcComponentID=new Guid(dr.Cells[0].Value.ToString());
                    if(this._FromComponents !=null && this._FromComponents.Length>0)
                    {
                        foreach(WorkflowComponentBase fromComponent in this._FromComponents)
                        {
                            if (fromComponent.ComponentID == srcComponentID)
                            {
                                string srcFieldName = dr.Cells[2].Value.ToString();
                                string tgtFieldName = dr.Cells[3].Value.ToString();
                                Type tgtFieldType =
                                    SimpleDataTypeUtil.ToSystemType(this._GlobalVariables[tgtFieldName].DataType);
                                Type srcFieldType = this.GetSrcFieldType(fromComponent, srcFieldName);
                                string codeSnippet = string.Empty;
                                if (this._TransformationCodeSnippetsByGlobalVarNames.ContainsKey(srcComponentID))
                                {
                                    Dictionary<string, Dictionary<string, string>> srcField_TgtField_Code =
                                        this._TransformationCodeSnippetsByGlobalVarNames[srcComponentID];
                                    if (srcField_TgtField_Code.ContainsKey(srcFieldName))
                                    {
                                        Dictionary<string, string> tgtField_Code =
                                            srcField_TgtField_Code[srcFieldName];
                                        if (tgtField_Code.ContainsKey(tgtFieldName))
                                        {
                                            codeSnippet = tgtField_Code[tgtFieldName];
                                        }
                                    }
                                }
                                ConverterFactory converter = new ConverterFactory(e.RowIndex, srcFieldType, tgtFieldType,
                                                                                  codeSnippet);
                                converter.CodeSnippetUpdatedEvent +=
                                    new CodeSnippetUpdated(converter_CodeSnippetUpdatedEvent);
                                converter.Show(this);
                                break;
                            }
                        }
                    }
                    
                }
            }
        }

        void converter_CodeSnippetUpdatedEvent(int idx, string code)
        {
            if (idx >= 0 && idx < this.dv_Bindings.Rows.Count)
            {
                DataGridViewRow dr = this.dv_Bindings.Rows[idx];
                if (!dr.IsNewRow && dr.Cells[2].Value != null && dr.Cells[3].Value != null)
                {
                    Guid srcComponentID=new Guid(dr.Cells[0].Value.ToString());
                    string srcFieldName = dr.Cells[2].Value.ToString();
                    string tgtFieldName = dr.Cells[3].Value.ToString();
                    if (this._TransformationCodeSnippetsByGlobalVarNames.ContainsKey(srcComponentID))
                    {
                        Dictionary<string, Dictionary<string, string>> srcField_TgtField_Code =
                            this._TransformationCodeSnippetsByGlobalVarNames[srcComponentID];
                        if(srcField_TgtField_Code.ContainsKey(srcFieldName))
                        {
                            Dictionary<string, string> tgt_Code = srcField_TgtField_Code[srcFieldName];
                            if (!tgt_Code.ContainsKey(tgtFieldName))
                                tgt_Code.Add(tgtFieldName, code);
                            else
                                tgt_Code[tgtFieldName] = code;
                        }
                        else
                        {
                            Dictionary<string,string> tgtField_Code=new Dictionary<string, string>();
                            tgtField_Code.Add(tgtFieldName, code);
                            srcField_TgtField_Code.Add(srcFieldName,tgtField_Code);
                        }
                        this._TransformationCodeSnippetsByGlobalVarNames[srcComponentID] = srcField_TgtField_Code;
                    }
                    else
                    {
                        Dictionary<string, Dictionary<string, string>> srcField_TgtField_Code =
                            new Dictionary<string, Dictionary<string, string>>();
                        Dictionary<string, string> tgtField_Code = new Dictionary<string, string>();
                        tgtField_Code.Add(tgtFieldName, code);
                        srcField_TgtField_Code.Add(srcFieldName, tgtField_Code);
                        this._TransformationCodeSnippetsByGlobalVarNames.Add(srcComponentID, srcField_TgtField_Code);
                    }

                    DataGridViewImageCell cellTransform = (DataGridViewImageCell) dr.Cells[4];
                    cellTransform.Value = this.imageList1.Images[0];
                }
            }
        }

        public TestResult Test()
        {
            return new TestResult(true, string.Empty);
        }

        private void cbo_SrcComponents_SelectedIndexChanged(object sender, EventArgs e)
        {
            if(this.cbo_SrcComponents.SelectedIndex>=0)
            {
                string srcComponentName = this.cbo_SrcComponents.Text;
                foreach(WorkflowComponentBase srcComponent in this._FromComponents)
                {
                    if(srcComponent.ComponentName==srcComponentName)
                    {
                        this.lbl_SrcComponentID.Text = srcComponent.ComponentID.ToString();
                        this.PopulateSrcComponentOutputFields(srcComponent);
                        break;
                    }
                }
            }
        }

        private void PopulateSrcComponentOutputFields(WorkflowComponentBase fromComponent)
        {
            this.cbo_SrcFieldNames.Items.Clear();
            this.cbo_SrcFieldNames.SelectedIndex = -1;
            this.cbo_SrcFieldNames.Text = string.Empty;
            
            try
            {
                if (fromComponent.Output != null)
                {
                    Dictionary<string, Type> outputMember =
                        fromComponent.Output.GetBindableMemberNames(new Type[] { typeof(ResultBase) });
                    if (outputMember != null && outputMember.Count > 0)
                    {
                        foreach (string outputFieldName in outputMember.Keys)
                        {
                            this.cbo_SrcFieldNames.Items.Add(outputFieldName);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }

        }
    }
}